using System;
using System.Collections.Generic;
using System.Text;
using SystemFunctionLib.Apis;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

namespace SystemFunctionLib.Personalization
{
    /// <summary>
    /// Contains settings of the Desktop.
    /// </summary>
    public static class Display
    {
        private const uint NULL = 0;
        private const uint TRUE = 1;
        private const uint FALSE = 0;

        private const int MAX_PATH = 260;

        /// <summary>
        /// Gets or sets the filename of the desktop wallpaper. Empty string indicates there is no wallpaper.
        /// </summary>
        /// <remarks>
        /// Only .bmp files are supported in the versions earlier than Windows Vista.
        /// </remarks>
        public unsafe static string DesktopWallpaper
        {
            get
            {
                StringBuilder filename = new StringBuilder(MAX_PATH);
                
                bool successful = WinApis.SystemParametersInfo(
                    SPI.GetDeskWallpaper,
                    MAX_PATH,
                    filename,
                    SPIF.None);

                if (!successful)
                {
                    CoreApis.GetWinLastError();
                }

                return filename.ToString();
            }
            set
            {
                StringBuilder filename = new StringBuilder(value ?? string.Empty);

                bool successful = WinApis.SystemParametersInfo(
                    SPI.SetDeskWallpaper,
                    NULL,
                    filename,
                    SPIF.SendChange);

                if (!successful)
                {
                    throw CoreApis.GetWinLastError();
                }
            }
        }

        /// <summary>
        /// Gets or sets the method of rendering to smooth the font edges.
        /// </summary>
        public static FontSmoothingType FontSmoothingType
        {
            get
            {
                if (SystemInformation.IsFontSmoothingEnabled == false)
                {
                    return FontSmoothingType.None;
                }

                FONTSMOOTHINGTYPE type = (FONTSMOOTHINGTYPE)SystemInformation.FontSmoothingType;

                if (type == FONTSMOOTHINGTYPE.ClearType)
                {
                    return FontSmoothingType.ClearType;
                }
                else
                {
                    return FontSmoothingType.Standard;
                }
            }
            set
            {
                if (value == FontSmoothingType.None)
                {
                    // Turn off font smoothing
                    bool successful = WinApis.SystemParametersInfo(
                        SPI.SetFontSmoothing,
                        FALSE,
                        NULL,
                        SPIF.SendChange);
                }
                else
                {
                    // Turn on font smoothing
                    bool successful = WinApis.SystemParametersInfo(
                        SPI.SetFontSmoothing,
                        TRUE,
                        NULL,
                        SPIF.SendChange);

                    if (!successful)
                    {
                        throw CoreApis.GetWinLastError();
                    }

                    FONTSMOOTHINGTYPE newType;
                    switch (value)
                    {
                        case FontSmoothingType.Standard:
                            newType = FONTSMOOTHINGTYPE.Standard;
                            break;

                        case FontSmoothingType.ClearType:
                            newType = FONTSMOOTHINGTYPE.ClearType;
                            break;

                        default:
                            throw new ArgumentException();
                    }

                    successful = WinApis.SystemParametersInfo(
                        SPI.SetFontSmoothingType,
                        NULL,
                        (uint)newType,
                        SPIF.SendChange);

                    if (!successful)
                    {
                        CoreApis.GetWinLastError();
                    }
                }
            }
        }

        /// <summary>
        /// Default value of the <see cref="FontSmoothingContrast"/>.
        /// </summary>
        public const int FontSmoothingContrastDefault = 1400;

        /// <summary>
        /// Minimum value of the <see cref="FontSmoothingContrast"/>.
        /// </summary>
        public const int FontSmoothingContrastMinValue = 1000;

        /// <summary>
        /// Maximum value of the <see cref="FontSmoothingContrast"/>.
        /// </summary>
        public const int FontSmoothingContrastMaxValue = 2200;

        /// <summary>
        /// Gets or sets the contrast value used in ClearType smoothing. Valid contrast value are defined
        /// by <see cref="FontSmoothingContrastMinValue"/> and <see cref="FontSmoothingContrastMaxValue"/>.
        /// The default value is <see cref="FontSmoothingContrastDefault"/>.
        /// </summary>
        /// <remarks>
        /// This is not supported by Windows 2000.
        /// </remarks>
        public unsafe static int FontSmoothingContrast
        {
            get
            {
                return SystemInformation.FontSmoothingContrast;
            }
            set
            {
                uint contrast = (uint)Math.Min(
                    Math.Max(value, FontSmoothingContrastMinValue), 
                    FontSmoothingContrastMaxValue);

                bool successful = WinApis.SystemParametersInfo(
                    SPI.SetFontSmoothingContrast,
                    NULL,
                    contrast,
                    SPIF.SendChange);

                if (!successful)
                {
                    throw CoreApis.GetWinLastError();
                }
            }
        }

        /// <summary>
        /// Gets or sets the font smoothing orientation.
        /// </summary>
        /// <remarks>
        /// This is not supported until Windows XP with SP2.
        /// </remarks>
        public unsafe static FontSmoothingOrientation FontSmoothingOrientation
        {
            get
            {
                FONTSMOOTHINGORIENTATION orientation = 0;

                WinApis.SystemParametersInfo(
                    SPI.GetFontSmoothingOrientation,
                    NULL,
                    (void*)&orientation,
                    SPIF.None);

                return (FontSmoothingOrientation)orientation;
            }
            set
            {
                FONTSMOOTHINGORIENTATION orientation = (FONTSMOOTHINGORIENTATION)value;

                WinApis.SystemParametersInfo(
                    SPI.SetFontSmoothingOrientation,
                    NULL,
                    (uint)orientation,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets the size of the work area on the primary display monitor. The work area is the portion 
        /// of the screen not obscured by the system taskbar or by application desktop toolbars.
        /// </summary>
        /// <returns>A <see cref="Rectangle"/> that indicates the work area.</returns>
        public static Rectangle GetWorkArea()
        {
            return SystemInformation.WorkingArea;
        }

        /// <summary>
        /// Sets the size of the work area. The work area is the portion of the screen not obscured by 
        /// the system taskbar or by application desktop toolbars.
        /// </summary>
        /// <param name="rect">A <see cref="Rectangle"/> that is the new work area.</param>
        /// <returns>A <see cref="bool"/> value that indicates whether the operation is successfully
        /// performed.</returns>
        public unsafe static bool SetWorkArea(Rectangle rect)
        {
            RECT newRect = new RECT(rect);
            bool successful = WinApis.SystemParametersInfo(
                SPI.SetWorkArea,
                NULL,
                (void*)&newRect,
                SPIF.SendChange);

            return successful;
        }

        /// <summary>
        /// Gets or sets a <see cref="bool"/> value that indicates whether the drop shadow effect is enabled.
        /// </summary>
        /// <remarks>
        /// Not supported in Windows 2000.
        /// </remarks>
        public static bool ShowMenuDropShadow
        {
            get
            {
                return SystemInformation.IsDropShadowEnabled;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetDropShadow,
                    NULL,
                    value ? TRUE : FALSE,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets or sets a <see cref="bool"/> value that indicates whether native User menus have flat 
        /// menu appearance.
        /// </summary>
        /// <remarks>
        /// Not supported in Windows 2000.
        /// </remarks>
        public static bool ShowFlatMenu
        {
            get
            {
                return SystemInformation.IsFlatMenuEnabled;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetFlatMenu,
                    NULL,
                    value ? TRUE : FALSE,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets or sets the alignment value of pop-up menus, relative to the corresponding menu-bar item.
        /// </summary>
        public unsafe static MenuDropAlignment MenuDropAlignment
        {
            get
            {
                bool align = SystemInformation.RightAlignedMenus;
                return (align ? MenuDropAlignment.Right : MenuDropAlignment.Left);
            }
            set
            {
                uint align = FALSE;
                switch (value)
                {
                    case MenuDropAlignment.Left:
                        align = FALSE;
                        break;
                    case MenuDropAlignment.Right:
                        align = TRUE;
                        break;
                }

                WinApis.SystemParametersInfo(
                    SPI.SetMenuDropAlignment,
                    align,
                    NULL,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets or sets the animation used to display menus.
        /// </summary>
        public unsafe static MenuAnimation MenuAnimation
        {
            get
            {
                if (!SystemInformation.IsMenuAnimationEnabled)
                {
                    return MenuAnimation.None;
                }

                if (SystemInformation.IsMenuFadeEnabled)
                {
                    return MenuAnimation.Fade;
                }
                else
                {
                    return MenuAnimation.Slide;
                }
            }
            set
            {
                if (value == MenuAnimation.None)
                {
                    WinApis.SystemParametersInfo(
                        SPI.SetMenuAnimation,
                        NULL,
                        FALSE,
                        SPIF.SendChange);
                }
                else
                {
                    WinApis.SystemParametersInfo(
                        SPI.SetMenuAnimation,
                        NULL,
                        TRUE,
                        SPIF.SendChange);

                    if (value == MenuAnimation.Fade)
                    {
                        WinApis.SystemParametersInfo(
                            SPI.SetMenuFade,
                            NULL,
                            TRUE,
                            SPIF.SendChange);
                    }
                    else if (value == MenuAnimation.Slide)
                    {
                        WinApis.SystemParametersInfo(
                            SPI.SetMenuFade,
                            NULL,
                            FALSE,
                            SPIF.SendChange);
                    }
                }
            }
        }

        /// <summary>
        /// Gets or sets a <see cref="int"/> number that indicates the system waits before displaying 
        /// a shortcut menu when the mouse cursor is over a submenu item (in milliseconds).
        /// </summary>
        public unsafe static int MenuShowDelay
        {
            get
            {
                return SystemInformation.MenuShowDelay;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetMenuShowDelay,
                    (uint)value,
                    NULL,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets or sets whether screen saving is enabled.
        /// </summary>
        public static bool IsScreenSaverEnabled
        {
            get
            {
                bool enabled = false;
                WinApis.SystemParametersInfo(
                    SPI.GetScreenSaverActive,
                    NULL,
                    ref enabled,
                    SPIF.None);

                return enabled;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetScreenSaverActive,
                    value ? TRUE : FALSE,
                    NULL,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets a <see cref="bool"/> value that indicates whether a screen saver is currently running 
        /// on the window station of the calling process.
        /// </summary>
        public static bool IsScreenSaverRunning
        {
            get
            {
                bool running = false;
                WinApis.SystemParametersInfo(
                    SPI.GetScreenSaverRunning,
                    NULL,
                    ref running,
                    SPIF.None);

                return running;
            }
        }

        /// <summary>
        /// Gets or sets whether the screen saver requires a password to display the Windows desktop.
        /// </summary>
        public static bool SecureScreenSaver
        {
            get
            {
                bool secure = false;
                WinApis.SystemParametersInfo(
                    SPI.GetScreenSaverSecure,
                    NULL,
                    ref secure,
                    SPIF.None);

                return secure;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetScreenSaverSecure,
                    value ? TRUE : FALSE,
                    NULL,
                    SPIF.SendChange);
            }
        }

        /// <summary>
        /// Gets or sets the screen saver time-out value, in seconds, that the system must be idle 
        /// before the screen saver activates.
        /// </summary>
        public unsafe static int ScreenSaverTimeOut
        {
            get
            {
                uint timeout = 0;
                WinApis.SystemParametersInfo(
                    SPI.GetScreenSaverTimeOut,
                    NULL,
                    (void*)&timeout,
                    SPIF.None);
                return (int)timeout;
            }
            set
            {
                WinApis.SystemParametersInfo(
                    SPI.SetScreenSaverTimeOut,
                    (uint)value,
                    NULL,
                    SPIF.SendChange);
            }
        }
    }
}
